﻿// -----------------------------------------------------------------------
// <copyright file="Triangle.cs" company="">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace Assignment_3.Scene.Basic_Shapes
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Assignment_3.GenericStructures;
    using Assignment_3.Raytracer;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class Triangle : Shape
    {
        public Vector a, b, c;

        private Vector normal{get; set;}
        /// <summary>
        /// Create a new triangle.  Please enter the co-ordinates in a counter-clockwise order from a to c
        /// </summary>
        /// <param name="a"> first point </param>
        /// <param name="b"> second point </param>
        /// <param name="c"> third point </param>
        public Triangle(Vector a, Vector b, Vector c)
        {
            this.a = a;
            this.b = b;
            this.c = c;

            this.normal = null;
        }

        /// <summary>
        /// Determines if a ray intersects with the object, and if it does, it return the normal vector.  If not, it return null
        /// </summary>
        /// <param name="rayVector"></param>
        /// <param name="distance"></param>
        /// <returns></returns>
        public override Vector getFirstIntersection(Ray r)
        {
            //P = point
            //E = position of eye
            //d = direction of ray
            //t= distance from eye
            //N = normal 
            //a,b,c = vertices
            //x = |(P-A)|+|(P-B)|+ |(P dot C)|
            //if x > 1, you missed. x == 1, hit edge, x < 1, you hit
            //P = point 
            double t = -((r.origin - this.a).DotProduct(calculateNormal(null,r))) / (r.direction.DotProduct(calculateNormal(null,r)));

            Vector P = r.origin+t*r.direction;

            if (isOnside(r.origin, a, b, P) && isOnside(r.origin, b, c, P) && isOnside(r.origin, c, a, P))
            {
                if (((r.origin - P) / r.direction).x > 0 || ((r.origin - P) / r.direction).y > 0 || ((r.origin - P) / r.direction).z > 0)
                {
                    return null;
                }
                return P;
            }
            else if (isOnside(r.origin, b, a, P) && isOnside(r.origin, c, b, P) && isOnside(r.origin, a, c, P))
            {
                if (((r.origin - P) / r.direction).x > 0 || ((r.origin - P) / r.direction).y > 0 || ((r.origin - P) / r.direction).z > 0)
                {
                    return null;
                }
                return P;
            }
            else
            {
                return null;
            }

        }

        protected bool isOnside(Vector p0, Vector t1, Vector t2, Vector intersectionPoint)
        {
            bool result = true;

            Vector n1 = Vector.CrossProduct((p0 - t2), (p0 - t1));
            n1 /= n1.Length();

            double d1 = -p0.DotProduct(n1);

            if ((intersectionPoint.DotProduct(n1) + d1) < 0)
            {
                result = false;
            }

            return result;
        }

        public override Vector calculateNormal(Vector intersectionPoint, Ray r)
        {
            if (this.normal != null)
            {
                if (this.normal.DotProduct(r.direction) < 0)
                {
                    return this.normal;
                }
                else
                {
                    return new Vector(0,0,0) - this.normal;
                }
            }
            else
            {
                this.normal = Vector.CrossProduct((this.a - this.b), (this.a - this.c));

                this.normal /= this.normal.Length();

                if (this.normal.DotProduct(r.direction) < 0)
                {
                    return this.normal;
                }
                else
                {
                    return new Vector(0,0,0) -this.normal;
                }
            }
            
        }

        private bool PointIntersects(Vector intersectionPoint, Ray r)
        {
            double t = -((r.origin-this.a).DotProduct(this.normal))/(r.direction.DotProduct(this.normal));

            Vector P = r.origin+t*r.direction;

            double x = (P-this.a).Length() + (P-this.b).Length() + (Vector.DotProduct(P,this.c));

            if (!intersectionPoint.equals(P))
            {
                return false;
            }
            else
            {
                if (isOnside(r.origin, a, b, P) && isOnside(r.origin, b, c, P) && isOnside(r.origin, c, a, P))
                {
                    return true;
                }
                else if (isOnside(r.origin, b, a, P) && isOnside(r.origin, c, b, P) && isOnside(r.origin, a, c, P))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        public override Ray getReflectedRay(Ray original, Vector intersectionPoint)
        {
            Ray reflectedRay = null;
            if (PointIntersects(intersectionPoint, original))
            {
                Vector normal = calculateNormal(intersectionPoint, original);
                double c1 = -Vector.DotProduct(normal, original.direction);
                reflectedRay = new Ray(intersectionPoint, original.direction + (2 * normal * c1));
                reflectedRay.direction /= reflectedRay.direction.Length();
            }

            return reflectedRay;
        }

        public override Ray getRefractedRay(Ray original, Vector intersectionPoint, double indexOfRefractionOutside = 1.00, double indexOfRefractionInside = 1.00)
        {
            if (this.properties.transparencyCoefficient < 1)
            {
                return new Ray(intersectionPoint, original.direction);
            }
            else
            {
                return null;
            }
        }
    }
}
